<template>
  <el-table :data="tableData" border :span-method="spanMethod">
    <el-table-column v-for="(item, index) in tableHeader" :key="index" :label="item" :prop="item"></el-table-column>
    <el-table-column label="价格">
      <template slot-scope="scope">
        <el-input v-model="scope.row.sale_price" size="small" @blur="handleInput"></el-input>
      </template>
    </el-table-column>
    <el-table-column label="库存">
      <template slot-scope="scope">
        <el-input v-model="scope.row.number" size="small" @blur="handleInput"></el-input>
      </template>
    </el-table-column>
    <el-table-column label="重量">
      <template slot-scope="scope">
        <el-input v-model="scope.row.weight" size="small" @blur="handleInput"></el-input>
      </template>
    </el-table-column>
  </el-table>
</template>

<script>
export default {
  // 全局感知
  name: "AttrDetail",

  // 模板依赖
  components: {},
  filters: {},

  // 接口
  props: {
    // 自定义属性列表
    attrList: {
      type: Array,
      required: true
    },
    // 自定义属性列表更新后的标识
    hash: {
      type: Number,
      required: true
    }
  },

  // 本地状态
  data () {
    return {
      tableData: this.genTableData(this.attrList),
      tableHeader: this.genTableHeader(this.attrList)
    };
  },
  computed: {},

  // 事件
  watch: {
    /**
     * 刷新表格数据
     * 属性编辑达成某种条件后重新生成 hash，此处监控 hash 值，hash 改变则重新生成表格数据
     * @event
     */
    hash () {
      this.tableHeader = this.genTableHeader(this.attrList)
      this.tableData = this.genTableData(this.attrList)
      this.$emit('attr', this.tableData)
    }
  },
  beforeCreate () { },
  created () { },
  beforeMount () { },
  mounted () {
    this.$emit('attr', this.tableData)
  },
  beforeUpdate () { },
  updated () { },
  beforeDestroy () { },
  destroyed () { },

  // 非响应式的属性
  methods: {
    /**
     * 生成表头属性
     * @param {Array} list 属性列表
     * @returns {Array} 自定义属性名列表
     */
    genTableHeader (list) {
      return list.map(item => item.name)
    },
    /**
     * 生成属性组合数据
     * @param {Array} lists 属性列表
     * @returns {Array} 多种自定义属性的组合结果
     */
    reArranging (lists) {
      if (!lists.length) return []
      return lists.map(attr =>
        attr.list.map(item => ({ [attr.name]: item.value }))) // 提取属性名与属性值：{'颜色': '红'}
        .reduce((listA, listB) => // 对各属性累加循环，不提供初始值
          listA.reduce((list, A) => // 对上一级的累积值进行累加循环，提供初始值 list = []，此处生成总的组合结果列表；A 为累积值的当前项：{'颜色': '红', '重量': '10', ...}
            list.concat( // 向累积值中添加新项
              listB.map(B => Object.assign({}, A, B)) // B 为新增的属性项: {'包装': '纸盒'}
            ), []))
    },
    /**
     * 合并新老数据
     * @param {Array} newData 生成的新数据
     * @param {Array} oldData 原有数据
     * @returns {Array} 合并后结果
     */
    mergeData (newData, oldData) {
      const requiredKeys = ['sale_price', 'number', 'weight']
      const customize = (data, list) => _.omit(data, list)
      return _.map(newData, newCustomize => {
        const oldCustomize = _.find(oldData, oldItem => _.isEqual(newCustomize, customize(oldItem, requiredKeys)))
        return oldCustomize || Object.assign({ sale_price: 0, number: 0, weight: 0 }, newCustomize)
      })
    },
    /**
     * 生成表格数据
     * @param {Array} lists 属性列表
     * @returns {Array} 属性表格数据
     */
    genTableData (lists) {
      const oldData = this.tableData
      const newData = this.reArranging(lists)
      return this.mergeData(newData, oldData)
    },
    /**
     * 表格行合并方法
     * @param {Object} _ 单元格的行数据、列数据、行索引、列索引
     * @returns {Array} 单元格合并栏数目 [合并行数，合并列数]
     */
    spanMethod ({ row, column, rowIndex, columnIndex }) {
      const { attrList } = this
      if (!attrList.length) return
      const len = attrList.map(item => item.list.length) // 所有自定义属性的项数列表 [属性A共3项, 属性B共2项, 属性C共4项,]
      const rowSpan = len.slice(columnIndex + 1).reduce((pro, item) => pro * item, 1) // 合并的行数，某属性需要合并的行数为其后的所有自定义属性项数乘积
      if (columnIndex >= len.length - 1) return [1, 1] // 根据列索引筛选出非自定义属性，即不需要合并行的属性
      if (rowIndex % rowSpan === 0) return [rowSpan, 1]
      else return [0, 0]
    },
    handleInput () {
      this.$emit('attr', this.tableData)
    }
  }
}
</script>

<style lang="less" scoped>

</style>